using System;
using System.Collections.Generic;
using System.Text;

namespace DemonHunter
{
    class Logic
    {
        private List<EventQueue> eventsQ;

        private double xLoc;
        private double speedModifier = 1;
        private double nextEventXLoc = -2;
        private PlayerCharacter player;
        private bool altKeyPressed = false;
        private bool spaceKeyPressed = false;
        private int currLevel = 0;

        private static Logic me;

        private Game game;

        public Logic()
        {
            me = this;
            game = Game.GetInstance();

            eventsQ = new List<EventQueue>();
            eventsQ.Add(new EventQueue("C:\\DemonHunterart\\desert\\desertEvent.xml"));
            eventsQ.Add(new EventQueue("C:\\DemonHunterart\\barrens\\barrensEvent.xml"));
            eventsQ.Add(new EventQueue("C:\\DemonHunterart\\outskirt\\outskirtEvent.xml"));
            eventsQ.Add(new EventQueue("C:\\DemonHunterart\\wall\\wallEvent.xml"));
        }

        public void StartNextLevel()
        {
            // remove all existing entities except player
            for (int i = 1; i < Level.GetInstance().GetNumEntities(); i++)
                Level.GetInstance().RemoveEntity(i);

            // load next level
            currLevel++;
            Level.GetInstance().SetBackgroundIndex(currLevel);
            xLoc = 0; // reset x variable
            nextEventXLoc = -2; // reset event queue location
        }

        public void DoLogic()
        {
            if (PlayerCharacter.GetInstance().GetHealth() <= 0) return;
            ListenForKeypress(); // check for keypresses          
            SetupThisIteration(); // move entities, etc.
            HandleEvent(); // check to see if a new event should begin
            
            //call draw functions
            game.DrawScenery(xLoc);
            game.DrawHero(player);
            game.DrawEntities(xLoc);

            //update xloc
            xLoc += 5 * speedModifier;
        }
        /// <summary>
        /// SetupThisIteration does all necessary work to prepare characters to be
        /// displayed to screen during this current iteration of the loop
        /// </summary>
        public void SetupThisIteration()
        {
            player = PlayerCharacter.GetInstance();

            // if nextEventXLoc = -2, it means the first event X location has not been read yet
            if (nextEventXLoc == -2) nextEventXLoc = eventsQ[currLevel].getNextEventXLoc();

            // speedModifier ensures the game runs the same speed on every computer
            if (game.GetFPS() > 0) speedModifier = 160 / (double)game.GetFPS();

            Entity.setSpeedModifier(speedModifier);

            Level level = Level.GetInstance();

            // animate and move all entities
            for (int i = 0; i < level.GetNumEntities(); i++)
            {
                Entity entity = level.GetEntity(i);
                entity.DoXIncrease();
                entity.animate();
                entity.move();
            }
        }
        /// <summary>
        /// ListenForKeypress checks to see if the player has pressed any keys
        /// if so, it prepares hero to be drawn to screen after taking appropriate
        /// action for that keypress
        /// </summary>
        public void ListenForKeypress()
        {
            if (game.KbKey[AllegNet.AllKeys.Right]) player.moveRight();
            if (game.KbKey[AllegNet.AllKeys.Left]) player.moveLeft();
            if (game.KbKey[AllegNet.AllKeys.Up]) player.moveUp();
            if (game.KbKey[AllegNet.AllKeys.Down]) player.moveDown();
            
            // see if gun should be fired
            if (game.KbKey[AllegNet.AllKeys.Space])
            {
                if (spaceKeyPressed == false && player.GetAmmo() > 0)
                {
                    spaceKeyPressed = true;
                    player.Attack();
                    DetectKill();
                    UI.GetInstance().Refresh();
                }
            }
            else
            {
                spaceKeyPressed = false;
            }

            // see if grenade should be dropped
            if (game.KbKey[AllegNet.AllKeys.Alt])
            {
                if (altKeyPressed == false && player.GetGrenades() > 0)
                {
                    altKeyPressed = true;
                    player.DropGrenade();
                    UI.GetInstance().Refresh();
                }
            }
            else
            {
                altKeyPressed = false;
            }
        }
        /// <summary>
        /// HandleEvent removes an event from the queue and sets backgroundIndex variable
        /// and populates levels entity queue accordingly
        /// </summary>
        public void HandleEvent()
        {
            if (nextEventXLoc != -1 && xLoc >= nextEventXLoc)
            {
                //get event
                Event currentEvent = eventsQ[currLevel].getNextEvent();
                currentEvent.Execute();

                nextEventXLoc = eventsQ[currLevel].getNextEventXLoc();
            }
        }
        /// <summary>
        /// DetectKill detects if an entity has been killed by gunfire and then removes
        /// them from the entity list so they are not drawn again.
        /// </summary>
        public void DetectKill()
        {
            Entity tmpEntity;
            Level level = Level.GetInstance();

            // check all entities (except player) to see if they have been shot
            for (int i = 1; i < level.GetNumEntities(); i++)
            {
                tmpEntity = level.GetEntity(i);
                if (player.getEntityXLoc() + player.GetCurrentBitmap().Width <= tmpEntity.getEntityXLoc() - (tmpEntity.GetCurrentBitmap().Width / 2) && tmpEntity.IsKillable())
                {
                    tmpEntity.ReduceHealth(5);
                    break; // only allow one enemy to be killed by gunfire per shot
                }
            }
        }

        public void DetectExplosionCollisions(Explosion exp)
        {
            Entity entity;
            Level level = Level.GetInstance();

            // check all entities (except player) to see if they have been hit by the explosion
            for (int i = 1; i < level.GetNumEntities(); i++)
            {
                entity = level.GetEntity(i);
                if (exp.getEntityXLoc() + exp.GetCurrentBitmap().Width > entity.getEntityXLoc() && exp.getEntityXLoc() + exp.GetCurrentBitmap().Width < entity.getEntityXLoc() + entity.GetCurrentBitmap().Width)
                    entity.ReduceHealth(10);
                else if (exp.getEntityXLoc() > entity.getEntityXLoc() && exp.getEntityXLoc() < entity.getEntityXLoc() + entity.GetCurrentBitmap().Width)
                    entity.ReduceHealth(10);
                else if (exp.getEntityXLoc() < entity.getEntityXLoc() && exp.getEntityXLoc() + exp.GetCurrentBitmap().Width > entity.getEntityXLoc())
                    entity.ReduceHealth(10);
            }

        }

        public double GetXLoc() { return xLoc; }

        public static Logic GetInstance() { return me; }
    }
}
